package cn.com.haopt.common.utils;

import java.util.Arrays;

/**
 * @author haopt
 * @version 1.0
 * @date 2021/4/8 10:12
 */
public class CrcCheck {

    /**
     * 内层 1021 对数据进行校验
     * CRC-CCITT (XModem)
     * CRC16_XMODEM：多项式x16+x12+x5+1（0x1021），初始值0x0000，低位在后，高位在前，结果与0x0000异或
     */
    public static byte[] innerCrc(byte[] req, int startIndex, int end) {
        byte[] reqDataCrc = Arrays.copyOfRange(req, startIndex, end);
        byte[] crc = new byte[2];
        int wCRCin = 0x0000;
        int wCPoly = 0x1021;
        for (byte b : reqDataCrc) {
            for (int i = 0; i < 8; i++) {
                boolean bit = ((b >> (7 - i) & 1) == 1);
                boolean c15 = ((wCRCin >> 15 & 1) == 1);
                wCRCin <<= 1;
                if (c15 ^ bit) {
                    wCRCin ^= wCPoly;
                }
            }
        }
        wCRCin &= 0xffff;
        wCRCin ^= 0x0000;
        crc[1] = (byte) (wCRCin);
        crc[0] = (byte) (wCRCin >> 8);
        return crc;
    }


    /**
     * 外层 8005 产生两位校验码
     *
     * @param a：
     * @param startIndex：
     * @param len：
     * @return
     */
    public static byte[] outCrc(byte[] a, int startIndex, int len) {
        int bLen = startIndex + len;
        int j;
        long regCrc = 0xffff;
        for (int i = startIndex; i < bLen; i++) {
            regCrc ^= a[i] & 0xFF;
            for (j = 0; j < 8; j++) {
                if ((regCrc & 0x01) == 1) {
                    regCrc = (regCrc >> 1) ^ 0xa001;
                } else {
                    regCrc = regCrc >> 1;
                }
            }
        }
        return new byte[]{(byte) (regCrc), (byte) (regCrc >> 8)};
    }

}
